//
//  TQQKuaiboTagView.swift
//  SwiftLearning
//
//  Created by 黄龙 on 2024/1/25.
//

import UIKit

//快播动画标签

class TQQKuaiboTagView: UIView {
    private var titleArr:[String] = []
    private var titleIndex:Int = 0
    private var timer:Timer?
    var fireInterval:CFTimeInterval = 2.0 //每隔n秒取新的title生成label并开始动画
    var duration:CFTimeInterval = 16.0
    var rowHeight = 35.0
    var font:UIFont = .systemFont(ofSize: 20)
    
    var tapBlock:os_block_string?
    
    init(frame:CGRect,titles:[String]){
        super.init(frame: frame)
        self.titleArr.append(contentsOf: titles)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func reloadDataAndQvod(titls:[String]){
        stopQvod()
        for perView in self.subviews{
            perView.layer.removeAllAnimations()
            perView.removeFromSuperview()
        }
        
        self.titleArr.removeAll()
        self.titleArr.append(contentsOf: titls)
//为免打开时没有数据，先取出2组数据，并让其动画快进一点
        self.titleIndex = 0
        fillSomeWhenShow(count: Int(duration/fireInterval)-2)
        startQvod()
    }
    
    func fillSomeWhenShow(count:Int){
        for i in 0 ..< count{
            if let buttonaRY = bubbleUp(){
                for perLabel in buttonaRY{
                    perLabel.setValue(Double(i+1)*fireInterval, forKeyPath: "timeoffset")
                    //timeOffset-增加timeOffset只是让动画快进到某一点，例如，对于一个持续1秒的动画来说，设置timeOffset为0.5意味着动画将从一半的地方开始
                }
            }
        }
    }
    
    func stopQvod(){
        if let timer = timer{
            timer.invalidate()
            self.timer = nil
        }
    }
    
    func startQvod(){
        self.timer = Timer.scheduledTimer(withTimeInterval: fireInterval, repeats: true, block: {[weak self] _ in
            let _ = self?.bubbleUp()
        })
        if let timer = self.timer{
            RunLoop.main.add(timer, forMode: .common)
            timer.fire()
        }
    }
    
    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
//显示动画过程，因为是layer在移动，label的frame实际是没有动的，这就会导致动画过程中无法响应touch事件
//此时需要重载处理,判断点击是否在layer.presentationLayer中
        for perLabel in self.subviews{
            if let rect = perLabel.layer.presentation()?.frame{
                if CGRectContainsPoint(rect, point){
                    return perLabel
                }
            }
            
        }
        return nil
    }

    
    //动画
   func bubbleUp()->[TQQTouchLabel]?{
       titleIndex = titleIndex % titleArr.count //取titles的当前序号，取%是方便titleIndex会一直往上加时也能取到正确的index，无需判断=count的时候重置为0
       let tmpTitles = self.continueGetShowTitles()
       
       var result:[TQQTouchLabel] = []
       for i in 0 ..< tmpTitles.count{
           let title = tmpTitles[i]
           let titleWidth = SwiftFunc.sizeWithText(title, font: font).width
           let label = TQQTouchLabel(frame: CGRect(x: self.bounds.width/2-titleWidth/2, y: self.bounds.height-rowHeight, width: titleWidth, height: rowHeight)) //初始显示在底部中间
           label.text = title
           label.delegate = self
           label.font = font
           label.textColor = .label
           label.isUserInteractionEnabled = true
           self.addSubview(label)
           result.append(label)
       }
       //根据label个数，重新调整各label的初始位置
       if 2 == result.count{ //2个label，则位置改为左右各一个
           let leftLabel = result[0]
           let rightLabel = result[1]
           let rect_1 = leftLabel.frame
           let rect_2 = rightLabel.frame
           //各一半居中
           result[0].frame = CGRect(x: self.bounds.width/4 - rect_1.width/2, y: rect_1.minY, width: rect_1.width, height: rect_1.height)
           result[1].frame = CGRect(x: self.bounds.width/4*3 - rect_2.width/2, y: rect_2.minY, width: rect_2.width, height: rect_2.height)
       }else if 3 == result.count{//3个label，则第1个和第3个放在两侧
           let rect_m = result[1].frame
           let rect_l = result[0].frame
           let rect_r = result[2].frame
           let leftSpace = rect_m.minX
           //中间不变，剩余两侧居中
           result[0].frame = CGRect(x: leftSpace/2 - rect_l.width/2, y: rect_l.minY, width: rect_l.width, height: rect_l.height)
           result[2].frame = CGRect(x: rect_m.maxX + leftSpace/2 - rect_r.width/2, y: rect_r.minY, width: rect_r.width, height: rect_r.height)
       }
       
       for i in 0 ..< result.count{
//配置每个label的动画
//先配置从底部往中的过程 从小到大，从隐到明
           let label = result[i]
           let basicScale = CABasicAnimation(keyPath: "transform.scale")
           basicScale.fromValue = 0.65
           basicScale.toValue = 1
           basicScale.autoreverses = true
           basicScale.duration = duration/2.0 //后半程刚好autoreverses
           basicScale.fillMode = .forwards
           basicScale.isRemovedOnCompletion = false
           basicScale.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
           label.layer.add(basicScale, forKey: "scale")
           
           let basicOpa = CABasicAnimation(keyPath: "opacity")
           basicOpa.fromValue = 0.3
           basicOpa.toValue = 1.0
           basicOpa.autoreverses = true
           basicOpa.duration = duration / 2
           basicOpa.fillMode = .forwards
           basicOpa.isRemovedOnCompletion = false
           basicOpa.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
           label.layer.add(basicOpa, forKey: "alpha")
           
           //然后就是移动的路径，中间label居中移动，两侧label向两侧移动
           let path = UIBezierPath()
           path.move(to: CGPoint(x: label.frame.midX, y: label.frame.midY))
           if 1 == result.count{
               path.addLine(to: CGPoint(x: label.frame.midX, y: rowHeight/2)) //居中走到顶部
           }else if 2 == result.count{
               if 0 == i{
                   path.addCurve(to: CGPoint(x: label.frame.midX, y: rowHeight/2), controlPoint1: CGPoint(x: label.frame.midX, y: label.frame.midY), controlPoint2: CGPoint(x: 0, y: self.bounds.height/2))//左label走左弧
               }else if 1 == i{
                   path.addCurve(to: CGPoint(x: label.frame.midX, y: rowHeight/2), controlPoint1: CGPoint(x: label.frame.midX, y: label.frame.midY), controlPoint2: CGPoint(x: self.bounds.width, y: self.bounds.height/2))//右label走右弧
               }
           }else if 3 == result.count{
               if 1 == i{
                   path.addLine(to: CGPoint(x: label.frame.midX, y: rowHeight/2)) //居中走到顶部
               }else if 0 == i{
                   path.addCurve(to: CGPoint(x: label.frame.midX, y: rowHeight/2), controlPoint1: CGPoint(x: label.frame.midX, y: label.frame.midY), controlPoint2: CGPoint(x: 0, y: self.bounds.height/2))//左label走左弧
               }else if 2 == i{
                   path.addCurve(to: CGPoint(x: label.frame.midX, y: rowHeight/2), controlPoint1: CGPoint(x: label.frame.midX, y: label.frame.midY), controlPoint2: CGPoint(x: self.bounds.width, y: self.bounds.height/2))//右label走右弧
               }
           }
//位置动画
           let keyPosi = CAKeyframeAnimation(keyPath: "position") //位置动画
           keyPosi.path = path.cgPath
           keyPosi.fillMode = .forwards
           keyPosi.isRemovedOnCompletion = false
           keyPosi.duration = duration
           keyPosi.delegate = self
           keyPosi.setValue(label, forKey: "itslayer")
           keyPosi.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
           label.layer.add(keyPosi, forKey: "xy")
           
       }
       
       return result
   }
    
    func rightArrIndex(index:Int)->Int{
        return index % titleArr.count
    }
//每次取1-3个title(根据title的宽度决定)用来播放展示
    func continueGetShowTitles()->[String]{
        var result:[String] = []
        var tmpIndex = titleIndex
        if let title_1 = titleArr.strIndex(tmpIndex){
            let width_1 = SwiftFunc.sizeWithText(title_1, font: font).width
            result.append(title_1)
            titleIndex += 1 //至少显示1条
            if width_1 > self.bounds.width{
                return result
            }
            
            tmpIndex +=  1
            if let title_2 = titleArr.strIndex(tmpIndex){
                let width_2 = SwiftFunc.sizeWithText(title_2, font: font).width
                if width_1 + width_2 > self.bounds.width{
                    return result //只显示1条
                }else{
                    titleIndex += 1
                    result.append(title_2) //显示2条
                }
                
                tmpIndex +=  1
                if let title_3 = titleArr.strIndex(tmpIndex){
                    let width_3 = SwiftFunc.sizeWithText(title_3, font: font).width
                    if width_1 + width_2 + width_3 > self.bounds.width{
                        return result //只显示2条
                    }else{
                        result.append(title_3)
                        titleIndex += 1
                        return result //显示3条
                    }
                }
            }
        }
        return result
    }
    
}

extension TQQKuaiboTagView : CAAnimationDelegate{
    func animationDidStart(_ anim: CAAnimation) {
        if let label = anim.value(forKeyPath: "itslayer") as? UIView{
            if let toffset = label.value(forKeyPath: "timeoffset") as? CFTimeInterval{
                //TQQTouchLabel本身是没有timeoffset的keyPath，要想kvo（timeoffset）需要增加 @objc var timeoffset:CFTimeInterval = 0
                label.layer.timeOffset = toffset
                //timeOffset-增加timeOffset只是让动画快进到某一点，例如，对于一个持续1秒的动画来说，设置timeOffset为0.5意味着动画将从一半的地方开始
            }
        }
    }
    
    func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
        if flag{
            if let label = anim.value(forKeyPath: "itslayer") as? UIView{
                label.layer.removeAllAnimations()
                label.removeFromSuperview() //结束从UI移除
            }
        }
    }
    
}

extension TQQKuaiboTagView:TQQTouchLabelDelegate{
    func touchDown(_ sender: TQQTouchLabel) {
    //按下时暂停动画
        let pausedTime = sender.layer.convertTime(CACurrentMediaTime(), from: nil)
        sender.layer.speed = 0.0
        sender.layer.timeOffset = pausedTime
    }
    
    func touchOut(_ sender: TQQTouchLabel) {
        //移开时继续动画
        let pausedTime = sender.layer.timeOffset
        sender.layer.speed = 1.0
        sender.layer.timeOffset = 0.0
        sender.layer.beginTime = 0.0
        let timeSincePause =  sender.layer.convertTime(CACurrentMediaTime(), from: nil) - pausedTime
        sender.layer.beginTime = timeSincePause
    }
    
    func touchUpInside(_ sender: TQQTouchLabel) {
        if let title = sender.text{
            print(String(format: "点击:%@", title))
            tapBlock?(title)
        }else{
            print("点击:Label")
        }
        
        touchOut(sender) //点击后继续移动
    }
    

    
}

extension Array{
    func strIndex(_ index:Index)->String?{
        return self[index % self.count] as? String
    }
}
